home *** CD-ROM | disk | FTP | other *** search
/ QRZ! Ham Radio 8 / QRZ Ham Radio Callsign Database - Volume 8.iso / mac / files / t_sys5 / 92052tar.gz / 920528.tar / icmpcmd.c < prev    next >
C/C++ Source or Header  |  1992-05-14  |  7KB  |  325 lines

  1. /* @(#) $Header: icmpcmd.c,v 1.11 92/05/14 13:20:04 deyke Exp $ */
  2.  
  3. /* ICMP-related user commands
  4.  * Copyright 1991 Phil Karn, KA9Q
  5.  */
  6. #include <stdio.h>
  7. #include <time.h>
  8. #include "global.h"
  9. #include "icmp.h"
  10. #include "ip.h"
  11. #include "mbuf.h"
  12. #include "netuser.h"
  13. #include "internet.h"
  14. #include "timer.h"
  15. #include "socket.h"
  16. #include "cmdparse.h"
  17. #include "commands.h"
  18.  
  19. #define NULLPING (struct ping *)0
  20. #define PMOD    7
  21.  
  22. /* ID fields for pings; indicates a oneshot or repeat ping */
  23. #define ONESHOT 0
  24. #define REPEAT  1
  25.  
  26. /* Hash table list heads */
  27. struct ping *ping[PMOD];
  28.  
  29. static int doicmpec __ARGS((int argc, char *argv[],void *p));
  30. static int doicmpstat __ARGS((int argc, char *argv[],void *p));
  31. static int doicmptr __ARGS((int argc, char *argv[],void *p));
  32. static int pingem __ARGS((int32 target,int seq,int id,int len));
  33. static void ptimeout __ARGS((void *p));
  34. static int16 hash_ping __ARGS((int32 dest));
  35. static struct ping *add_ping __ARGS((int32 dest));
  36. static void del_ping __ARGS((struct ping *pp));
  37.  
  38. static struct cmds Icmpcmds[] = {
  39.     "echo",         doicmpec,       0, 0, NULLCHAR,
  40.     "status",       doicmpstat,     0, 0, NULLCHAR,
  41.     "trace",        doicmptr,       0, 0, NULLCHAR,
  42.     NULLCHAR
  43. };
  44.  
  45. int Icmp_trace;
  46. static int Icmp_echo = 1;
  47.  
  48. int
  49. doicmp(argc,argv,p)
  50. int argc;
  51. char *argv[];
  52. void *p;
  53. {
  54.     return subcmd(Icmpcmds,argc,argv,p);
  55. }
  56.  
  57. static int
  58. doicmpstat(argc,argv,p)
  59. int argc;
  60. char *argv[];
  61. void *p;
  62. {
  63.     register int i;
  64.     int lim;
  65.  
  66.     /* Note that the ICMP variables are shown in column order, because
  67.      * that lines up the In and Out variables on the same line
  68.      */
  69.     lim = NUMICMPMIB/2;
  70.     for(i=1;i<=lim;i++){
  71.         printf("(%2u)%-20s%10lu",i,Icmp_mib[i].name,
  72.          Icmp_mib[i].value.integer);
  73.         printf("     (%2u)%-20s%10lu\n",i+lim,Icmp_mib[i+lim].name,
  74.          Icmp_mib[i+lim].value.integer);
  75.     }
  76.     return 0;
  77. }
  78. static int
  79. doicmptr(argc,argv,p)
  80. int argc;
  81. char *argv[];
  82. void *p;
  83. {
  84.     return setbool(&Icmp_trace,"ICMP tracing",argc,argv);
  85. }
  86. static int
  87. doicmpec(argc,argv,p)
  88. int argc;
  89. char *argv[];
  90. void *p;
  91. {
  92.     return setbool(&Icmp_echo,"ICMP echo response accept",argc,argv);
  93. }
  94.  
  95. /* Send ICMP Echo Request packets */
  96. int
  97. doping(argc,argv,p)
  98. int argc;
  99. char *argv[];
  100. void *p;
  101. {
  102.     int32 dest;
  103.     struct ping *pp1;
  104.     register struct ping *pp;
  105.     int16 hval;
  106.     int i;
  107.     int16 len;
  108.  
  109.     if(argc < 2){
  110.         printf("Host                Sent    Rcvd   %%   Srtt   Mdev  Length  Interval\n");
  111.         for(i=0;i<PMOD;i++){
  112.             for(pp = ping[i];pp != NULLPING;pp = pp->next){
  113.                 printf("%-16s",inet_ntoa(pp->target));
  114.                 printf("%8lu%8lu",pp->sent,pp->responses);
  115.                 printf("%4lu",
  116.                  (long)pp->responses * 100 / pp->sent);
  117.                 printf("%7lu", pp->srtt);
  118.                 printf("%7lu", pp->mdev);
  119.                 printf("%8u", pp->len);
  120.                 printf("%10lu\n",
  121.                  dur_timer(&pp->timer) / 1000);
  122.             }
  123.         }
  124.         return 0;
  125.     }
  126.     if(strcmp(argv[1],"clear") == 0){
  127.         for(i=0;i<PMOD;i++){
  128.             for(pp = ping[i];pp != NULLPING;pp = pp1){
  129.                 pp1 = pp->next;
  130.                 del_ping(pp);
  131.             }
  132.         }
  133.         return 0;
  134.     }
  135.     if((dest = resolve(argv[1])) == 0){
  136.         printf("Host %s unknown\n",argv[1]);
  137.         return 1;
  138.     }
  139.     if(argc > 2) {
  140.         len = atoi(argv[2]);
  141.         if (len < ICMPLEN) {
  142.             printf("packet size too small, minimum size is %d bytes\n", ICMPLEN);
  143.             return 1;
  144.         }
  145.     } else
  146.         len = 64;
  147.     /* See if dest is already in table */
  148.     hval = hash_ping(dest);
  149.     for(pp = ping[hval]; pp != NULLPING; pp = pp->next){
  150.         if(pp->target == dest){
  151.             break;
  152.         }
  153.     }
  154.     if(argc > 3){
  155.         /* Inter-ping time is specified; set up timer structure */
  156.         if(pp == NULLPING)
  157.             pp = add_ping(dest);
  158.         set_timer(&pp->timer, atoi(argv[3]) * 1000L);
  159.         pp->timer.func = ptimeout;
  160.         pp->timer.arg = pp;
  161.         pp->target = dest;
  162.         pp->len = len;
  163.         start_timer(&pp->timer);
  164.         pingem(dest,(int16)pp->sent++,REPEAT,len);
  165.     } else
  166.         pingem(dest,0,ONESHOT,len);
  167.  
  168.     return 0;
  169. }
  170.  
  171. /* Called by ping timeout */
  172. static void
  173. ptimeout(p)
  174. void *p;
  175. {
  176.     register struct ping *pp;
  177.  
  178.     /* Send another ping */
  179.     pp = (struct ping *)p;
  180.     pingem(pp->target,(int16)pp->sent++,REPEAT,pp->len);
  181.     start_timer(&pp->timer);
  182. }
  183. void
  184. echo_proc(source,dest,icmp,bp)
  185. int32 source;
  186. int32 dest;
  187. struct icmp *icmp;
  188. struct mbuf *bp;
  189. {
  190.     register struct ping *pp;
  191.     int16 hval;
  192.     int32 rtt,abserr;
  193.     struct timeval tv,timestamp;
  194.     struct timezone tz;
  195.  
  196.     /* Get stamp */
  197.     if(pullup(&bp,(char *)×tamp,sizeof(timestamp))
  198.      != sizeof(timestamp)){
  199.         /* The timestamp is missing! */
  200.         rtt = -1;
  201.     } else {
  202.         gettimeofday(&tv, &tz);
  203.         rtt = (tv.tv_sec  - timestamp.tv_sec ) * 1000 +
  204.               (tv.tv_usec - timestamp.tv_usec) / 1000;
  205.     }
  206.     free_p(bp);
  207.  
  208.     hval = hash_ping(source);
  209.     for(pp = ping[hval]; pp != NULLPING; pp = pp->next)
  210.         if(pp->target == source)
  211.             break;
  212.     if(pp == NULLPING || icmp->args.echo.id != REPEAT){
  213.         if(!Icmp_echo)
  214.             return;
  215.         printf(
  216.           (rtt == -1) ?
  217.             "%s: echo reply id %u seq %u\n" :
  218.             "%s: echo reply id %u seq %u, %lu ms\n",
  219.           inet_ntoa(source),
  220.           icmp->args.echo.id,icmp->args.echo.seq,
  221.           (long)rtt);
  222.     } else {
  223.         /* Repeated poll, just keep stats */
  224.         pp->responses++;
  225.         if (rtt == -1)
  226.             return;
  227.         if(pp->responses == 1){
  228.             /* First response, base entire SRTT on it */
  229.             pp->srtt = rtt;
  230.         } else {
  231.             abserr = rtt > pp->srtt ? rtt - pp->srtt : pp->srtt - rtt;
  232.             pp->srtt = (7*pp->srtt + rtt + 4) >> 3;
  233.             pp->mdev = (3*pp->mdev + abserr + 2) >> 2;
  234.         }
  235.     }
  236. }
  237. /* Send ICMP Echo Request packet */
  238. static int
  239. pingem(target,seq,id,len)
  240. int32 target;   /* Site to be pinged */
  241. int16 seq;      /* ICMP Echo Request sequence number */
  242. int16 id;       /* ICMP Echo Request ID */
  243. int16 len;      /* Length of data field */
  244. {
  245.     struct mbuf *data;
  246.     struct mbuf *bp;
  247.     struct icmp icmp;
  248.     int i;
  249.     struct timeval tv;
  250.     struct timezone tz;
  251.  
  252.     if ((data = alloc_mbuf(len)) == NULLBUF)
  253.         return -1;
  254.     for (i = ICMPLEN; i < len; i++)
  255.         data->data[i] = i;
  256.     data->data += ICMPLEN;
  257.     data->cnt = len - ICMPLEN;
  258.     /* Insert timestamp and build ICMP header */
  259.     if (len >= ICMPLEN + sizeof(struct timeval)) {
  260.         gettimeofday(&tv, &tz);
  261.         memcpy(data->data, &tv, sizeof(struct timeval));
  262.     }
  263.     icmpOutEchos++;
  264.     icmpOutMsgs++;
  265.     icmp.type = ICMP_ECHO;
  266.     icmp.code = 0;
  267.     icmp.args.echo.seq = seq;
  268.     icmp.args.echo.id = id;
  269.     if((bp = htonicmp(&icmp,data)) == NULLBUF){
  270.         free_p(data);
  271.         return 0;
  272.     }
  273.     return ip_send(INADDR_ANY,target,ICMP_PTCL,0,0,bp,len,0,0);
  274. }
  275. static int16
  276. hash_ping(dest)
  277. int32 dest;
  278. {
  279.     int16 hval;
  280.  
  281.     hval = (hiword(dest) ^ loword(dest)) % PMOD;
  282.     return hval;
  283. }
  284. /* Add entry to ping table */
  285. static
  286. struct ping *
  287. add_ping(dest)
  288. int32 dest;
  289. {
  290.     struct ping *pp;
  291.     int16 hval;
  292.  
  293.     pp = (struct ping *)calloc(1,sizeof(struct ping));
  294.     if(pp == NULLPING)
  295.         return NULLPING;
  296.  
  297.     hval = hash_ping(dest);
  298.     pp->prev = NULLPING;
  299.     pp->next = ping[hval];
  300.     if(pp->next != NULLPING)
  301.         pp->next->prev = pp;
  302.     ping[hval] = pp;
  303.     return pp;
  304. }
  305. /* Delete entry from ping table */
  306. static void
  307. del_ping(pp)
  308. struct ping *pp;
  309. {
  310.     int16 hval;
  311.  
  312.     stop_timer(&pp->timer);
  313.  
  314.     if(pp->next != NULLPING)
  315.         pp->next->prev = pp->prev;
  316.     if(pp->prev != NULLPING) {
  317.         pp->prev->next = pp->next;
  318.     } else {
  319.         hval = hash_ping(pp->target);
  320.         ping[hval] = pp->next;
  321.     }
  322.     free(pp);
  323. }
  324.  
  325.